home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
MOTOROLA
/
6805V107
/
68705DBG.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-01-22
|
40KB
|
1,090 lines
{This module implements the 68705 Instruction Emulator}
{Revision 1.02 Fixes bugs in the ROL and ROR instructions}
{Revision 1.03 Displays time to execute programs}
type {Instruction Execution results}
InstRes = (Success, Illegal, StopInst, WaitInst, StackError);
BPelement = record {Breakpoint controls}
movedopc : byte; {Displaced opcode}
location : integer; {Its location}
end;
var
Commandline : string[255]; {NB Make longer in Original}
ComPtr : integer; {Pointer into Commandline}
valtab : array[0..255] of byte; {Collect line-input data}
valptr : integer; {Pointer for above}
low : integer; {Start point for Display}
BPlist : array[0..0] of BPelement; {Breakpoint table}
SimTime : real; {Count of machine cycles}
const
ResetVec = -1; {Vector locns., offset below MEMMAX}
SWIVec = -3; {Address the MS byte}
separator : set of char = [' ', ',', ^I]; {Debug command syntax}
Function memdat(loc :integer) :byte; {Byte from memory}
begin
memdat:= memory[loc and memmax];
end;
Procedure showcause(reason :InstRes); {Report execution failure}
begin
case reason of
{ Success: } {No report if Success}
Illegal: writeln('Illegal Op-Code');
StopInst: writeln('STOP Instruction');
WaitInst: writeln('WAIT Instruction');
StackError: writeln('Stack Over/Underflow');
end
end;
Function KeyStop : boolean; {Handles ^S and ^C}
function testit :char; {Inner control-key tester}
var
x : char;
begin
if keypressed then begin
read(kbd,x); {Pick up the key}
if x =^C then KeyStop:= true;
testit:= x;
end
else
testit:= ^L; {Anything not ^S or ^C}
end;
var
key : char;
begin
KeyStop:= false;
key:= testit;
if key =^S then repeat
key:= testit;
until key in [^S, ^C];
end;
Procedure ClearLine; {Sets PREFIX to Blanks}
begin
str(0:78,prefix);
prefix[78]:= ' ';
end;
Procedure ReportError; {Report errors in Command}
begin
writeln('Command error: type "H <CR>" for Help');
end;
Procedure PassGap; {Skip whitespace, etc.}
begin
while Commandline[ComPtr] in separator do ComPtr:= ComPtr+1;
end;
Function Getvalue(var ans :integer) :boolean; {Get hex. value}
begin
Getvalue:= false; {Check legal hex. no.}
ans := 0;
while hex(Commandline[ComPtr]) >= 0 do begin
Getvalue:= true;
ans:= (ans shl 4) + hex(Commandline[ComPtr]);
ComPtr:= ComPtr+1;
end;
PassGap;
end;
Function Getaddr (var x : integer) : boolean; {Get & validate an address}
begin
if Getvalue(x) then Getaddr:= (x >= 0) and (memmax >= x)
else Getaddr:= false;
end;
Function Getbytes : boolean; {Get list of bytes to table}
var
temp : integer;
OK : boolean;
begin
valptr:= 0;
OK := true;
while OK and (Commandline[ComPtr] <> CR) do begin
if Getvalue(temp) then begin {Get a value}
if hi(temp) =0 then begin
valtab[valptr]:= lo(temp);
valptr:= valptr+1;
end
else
OK:= false;
end
else
OK:= false;
end;
Getbytes:= OK;
end;
Function Getrange(var start, ending :integer) :boolean; {Get legal range}
begin
if Getvalue(start) then begin
Getrange:= true; {Got start value}
if Commandline[ComPtr] ='L' then begin {Range by Length}
ComPtr:= ComPtr+1; {Pass the "L"}
PassGap; {And any following whitespace}
Getrange:= Getvalue(ending);
ending:= ending + start -1; {Start & Ending inclusive}
end
else if Commandline[ComPtr] =CR then begin
ending:= start + 127; {No span - default 128}
if ending > memmax then ending:= memmax;
end
else
Getrange:= Getvalue(ending); {Explicit start & end}
if not ((start >= 0) and {Range validation}
(ending >= start) and
(memmax >= ending)) then Getrange:= false;
end
else
Getrange:= false; {Input error}
end;
Procedure GetLine(full :boolean); {Read the Command Line}
begin
clreol;
if full then write('>');
readln(Commandline);
if Commandline ='' then Commandline:= ' ';
for ComPtr:= 1 to length(Commandline) do {Case insensitive}
Commandline[ComPtr]:= upcase(Commandline[ComPtr]);
CommandLine:= Commandline + CR;
if full then begin
ComPtr:= 2;
while Commandline[ComPtr] in upper do ComPtr:= ComPtr+1;
end
else
ComPtr:= 1; {If subsidiary call, read everything}
PassGap; {To first significant field}
end;
function hardware :CRTptr; {CRT page base, via hardware}
const
monochrome =7;
Dmode : byte = monochrome; {Typed consts. in CS (Turbo-3}
Dpage : byte = 0; {They WILL be altered at run-time}
begin
inline ( {Access the ROM to find Monitor type}
$55/ {Push BP }
$B4/$0F/ {Mov AH,0F }
$CD/$10/ {Int 10 - CRT }
$2E/ {CS: }
$A2/Dmode/ {Mov [Dmode],AL }
$2E/ {CS: }
$88/$3E/Dpage/ {Mov [Dpage],BH }
$5D ); {Pop BP }
if (Dmode =monochrome) then
hardware:= Ptr($B000, 0)
else
hardware:= Ptr(($B800 + Dpage*256), 0);
end;
{********* R E G I S T E R - D I S P L A Y F U N C T I O N *************}
const
Hflag = $10; {Condition-Code bit values}
Iflag = 8;
Nflag = 4;
Zflag = 2;
Cflag = 1;
TDR = 8; {Locn. of Timer Data Reg.}
TCR = 9; {Locn. of Timer Control Reg.}
var {The actual machine registers}
AReg, {Accumulator}
XReg, {Index Reg.}
SReg, {Stack Pointer}
CReg : byte; {Condition-code Reg.}
PReg : integer; {Program Counter}
Procedure IntzRegs; {Cold-Start setups for Register functions}
begin {i.e. Simulate a Machine Reset}
PReg:= (memory[memmax+ResetVec] shl 8) + memory[memmax+ResetVec+1];
SReg:= StackTop; {Reset Stack Ptr.}
memory[TCR]:= memory[TCR] and $7f or $40; {TCR7:= 0, TCR6:= 1}
memory[4]:= 0;
memory[5]:= 0; {All DDR's to Input}
memory[6]:= 0;
memory[7]:= 0;
CReg := CReg or Iflag or $e0; {Interrupts masked}
end;
Procedure DisplayAllRegisters; {Standard display line - Used also by Trace}
const
flagnames : array[1..5] of char = ('H', 'I', 'N', 'Z', 'C');
type
RSize = (isbyte, isword); {Register Size}
leads = string[2];
Procedure OneReg(name :leads; regto :integer; howbig :RSize);
begin
hexword(1,regto); {Make it hex.}
lowvideo;
write(name);
highvideo;
if howbig = isbyte then write(copy(prefix,3,2))
else write(copy(prefix,1,4)); {Write byte or word}
write(' '); {2 blanks after}
end;
var
flagmask : byte;
flagcnt : integer;
const
instlen : array[0..15] of byte = (3,2,2,2,1,1,2,1,1,1,2,2,3,3,2,1);
begin
write(' '); {Set-over on line}
prefix[0]:= chr(16); {Room to display}
OneReg('A=',AReg,isbyte);
OneReg('X=',XReg,isbyte);
OneReg('P=',PReg,isword);
prefix:= '[@@ -- --] ';
hexbyte(2,memdat(PReg+0)); {Show 3 bytes after P reg}
flagcnt:= instlen[(memdat(PReg) shr 4) and 15];
if flagcnt > 1 then hexbyte(5,memdat(PReg+1));
if flagcnt = 3 then hexbyte(8,memdat(PReg+2));
lowvideo;
write(prefix);
OneReg('S=',SReg,isbyte);
OneReg('C=',CReg,isbyte); {Registers, in Hex.}
lowvideo;
write('[ '); {Ready for Conditions}
flagmask:= Hflag; {Test mask for 1st flag}
for flagcnt:= 1 to 5 do begin
if (CReg and flagmask) =0 then lowvideo
else highvideo; {Display mode}
write(flagnames[flagcnt], ' ');
flagmask:= flagmask shr 1;
end;
lowvideo;
writeln(']');
highvideo;
end;
Procedure DisplayRegisters; {The Display Regs. command}
var
temp : integer;
procedure EditReg(var reg :byte);
begin
prefix:= ' @@: ';
hexbyte(2,reg);
write(Commandline[ComPtr], prefix); {Display current value}
GetLine(false); {Use Command Line for data}
if CommandLine[ComPtr] <> CR then begin
if GetValue(temp) then begin
if hi(temp) =0 then reg:= temp {Good value - set Reg.}
else ReportError;
end
else
ReportError;
end
end;
begin
case Commandline[ComPtr] of {Which register?}
^M : DisplayAllRegisters;
'A' : EditReg(AReg);
'X' : EditReg(XReg);
'P' : begin
prefix:= ' @@@@: ';
hexword(2,PReg);
write(Commandline[ComPtr], prefix); {Display current value}
GetLine(false); {Use Command Line for data}
if CommandLine[ComPtr] <> CR then begin
if GetValue(temp) then PReg:= temp {Good value - set Reg.}
else ReportError;
end
end;
'S' : EditReg(SReg);
'C' : EditReg(CReg);
else ReportError;
end
end;
{**************************************************************************}
{***** I N S T R U C T I O N - E X E C U T I O N E M U L A T O R ********}
Function OneInstruction :InstRes; {Execute one instruction - result}
type
byteptr = ^byte;
var
opptr : byteptr; {Can point to Memory or Register}
localop : array[0..2] of byte; {Local copy of Instr.}
x,
msn, {Most & Least significant opcode nibbles}
lsn,
opaddr : integer; {Addr. in Memory of operand}
bitmask : byte; {Used by the Bit instructions}
Procedure PUSH (x :byte); {Push X to Stack: check overflow}
begin
if SReg < StackBottom then
OneInstruction := StackError
else begin
memory[SReg]:= x;
SReg:= SReg -1;
end
end;
Function POP :byte; {Pop a byte off Stack: check underflow}
begin
if SReg < StackTop then begin
SReg:= SReg +1;
POP := memory[SReg];
end
else OneInstruction:= StackError;
end;
Function extend(x :byte) :integer; {Sign extension}
begin
if (x and $80) =0 then extend:= x
else extend:= x + $ff00;
end;
Function bytad (var x :byte) :byteptr; {Returns the adrress of "x"}
begin {Must use "var", to get ptr.}
bytad:= Ptr(Seg(x), Ofs(x));
end;
Procedure Arithop (result :integer; CYlit, CYdata, saveans :boolean);
begin {Basic Operations}
if saveans then opptr^ := lo(result); {Always sets N and Z flags}
if (result and $80) =0 then CReg:= CReg and not Nflag
else CReg:= CReg or Nflag;
if lo(result) =0 then CReg:= CReg or Zflag
else CReg:= CReg and not Zflag;
if not CYlit then begin
if CYdata then CYdata:= (result and $ff00) <> 0
else CYdata:= (CReg and Cflag) <> 0;
end; {C flag is set by variable means}
if CYdata then CReg:= CReg or Cflag
else CReg:= CReg and not Cflag;
end;
const {Branch-condition selectors}
branchtest : array[0..7] of byte = (0,3,1,2,$10,4,8,0);
var
tempres : integer; {Partial result in instruction}
halfcar : byte; {Holds the half-carry}
begin {Start of OneInstruction}
for x:= 0 to 2 do localop[x]:= memory[(PReg+x) mod memmax];
msn:= (localop[0] shr 4) and 15;
lsn:= localop[0] and 15;
with ExTable[msn] do begin
if cycles[lsn] >0 then begin {Check its a legal opcode}
OneInstruction:= Success;
SimTime:= SimTime + cycles[lsn]; {Advance cycle counter}
PReg:= PReg +bytes; {Advance Instr. pointer}
case admode of {Addressing modes}
BTB: begin
opaddr:= localop[1];
opptr := bytad(memory[opaddr]);
end;
BSC: begin
opaddr:= localop[1];
opptr := bytad(memory[opaddr]);
end;
REL: begin
opaddr:= PReg+ extend(localop[1]);
opptr := bytad(memory[opaddr]);
end;
IMM: begin
opaddr:= PReg -1;
opptr := bytad(memory[opaddr]);
end;
DIR: begin
opaddr:= localop[1];
opptr := bytad(memory[opaddr]);
end;
EXT: begin
opaddr:= (localop[1] shl 8) + localop[2];
opptr := bytad(memory[opaddr]);
end;
IX: begin
opaddr:= XReg;
opptr := bytad(memory[opaddr]);
end;
IX1: begin
opaddr:= XReg + localop[1];
opptr := bytad(memory[opaddr]);
end;
IX2: begin
opaddr:= XReg + (localop[1] shl 8) + localop[2];
opptr := bytad(memory[opaddr]);
end;
INHX: opptr := bytad(XReg);
INHA: opptr := bytad(AReg);
end; {End the CASE}
case opclass of {Now execute the Instruction}
BitTest: begin {BIT TEST & BRANCH}
bitmask:= 1 shl (lsn div 2);
if (opptr^ and bitmask) <>0 then CReg:= CReg or Cflag
else CReg:= CReg and not Cflag;
{Conditional Branch}
if ((CReg and Cflag) <>0) xor odd(lsn) then
PReg:= PReg + extend(localop[2]);
end;
BitSetClr : begin {BIT SET / CLEAR}
bitmask:= 1 shl (lsn div 2);
if odd(lsn) then opptr^ := opptr^ and not bitmask
else opptr^ := opptr^ or bitmask;
end;
BranchRel : begin {CONDITIONAL, RELATIVE BRANCH}
if ((CReg and branchtest[lsn div 2]) =0) xor odd(lsn) then
PReg:= opaddr;
end;
RdModWrt : begin {READ/MODIFY/WRITE GROUP}
case lsn of {Operations}
0: Arithop(-opptr^, false, true, true);
3: Arithop(not opptr^, true, true, true);
4: Arithop((opptr^ shr 1) and 127, true, odd(opptr^), true);
6: begin
if ((CReg and Cflag) <>0) then tempres:= opptr^ + 256
else tempres:= opptr^;
Arithop(tempres shr 1, true, odd(opptr^), true);
end;
7: Arithop(extend(opptr^) shr 1, true, odd(opptr^), true);
8: Arithop(opptr^ shl 1, true, (opptr^ > 127), true);
9: begin
tempres:= CReg and 1; {Carry bit}
Arithop((opptr^ shl 1)+tempres, true, (opptr^ > 127), true);
end;
10: Arithop(opptr^ -1, false, false, true);
12: Arithop(opptr^ +1, false, false, true);
13: Arithop(opptr^, false, false, true);
15: Arithop(0, false, false, true);
end {End the R-M-W Case}
end; {End the R-M-W main block}
Control: begin {CONTROL OPERATIONS GROUP}
case localop[0] of {Miscellaneous - direct opcode}
$80: begin {RTI}
CReg:= POP;
AReg:= POP;
XReg:= POP;
PReg:= POP; {PReg needs 2 bytes}
PReg:= (PReg shl 8) + POP;
end;
$81: begin {RTS}
PReg:= POP;
PReg:= (PReg shl 8) + POP;
end;
$83: begin {SWI}
PUSH (lo(PReg));
PUSH (hi(PReg));
PUSH (XReg);
PUSH (AReg);
PUSH (CReg);
CReg:= CReg or Iflag; {Interrupts OFF}
PReg:= (memory[memmax+SWIVec] shl 8) +
memory[memmax+SWIVec+1];
end;
$8E: begin {STOP}
OneInstruction:= StopInst;
CReg:= CReg and not Iflag;
end;
$8F: begin {WAIT}
OneInstruction:= WaitInst;
CReg:= CReg and not Iflag;
end;
$97: XReg:= AReg; {TAX}
$98: CReg:= CReg and not Cflag; {CLC}
$99: CReg:= CReg or Cflag; {SEC}
$9A: CReg:= CReg and not Iflag; {CLI}
$9B: CReg:= CReg or Iflag; {SEI}
$9C: SReg:= $7F; {RSP}
{ $9D: NOP}
$9F: AReg:= XReg; {TXA}
end
end;
RegMem: begin {REGISTER - MEMORY GROUP}
tempres:= opptr^; {Get operand}
opptr := bytad(AReg); {Most results -> A}
case lsn of
0 : Arithop(AReg-tempres, false, true, true );
1 : Arithop(AReg-tempres, false, true, false);
2 : Arithop(Areg-tempres-
(CReg and Cflag), false, true, true );
3 : Arithop(XReg-tempres, false, true, false);
4 : Arithop(AReg and tempres, false, false, true );
5 : Arithop(AReg and tempres, false, false, false);
6 : Arithop(tempres, false, false, true );
7 : begin
opptr:= bytad(memory[opaddr]);
Arithop(AReg, false, false, true );
end;
8 : Arithop(AReg xor tempres, false, false, true );
9 : begin
halfcar:= ((AReg and 15) +
(tempres and 15) +
(CReg and Cflag) ) and Hflag;
Arithop(AReg+tempres+
(CReg and Cflag), false, true, true );
CReg:= (CReg and not Hflag) + halfcar;
end;
$A : Arithop(AReg or tempres, false, false, true );
$B : begin
halfcar:= ((AReg and 15) +
(tempres and 15)) and Hflag;
Arithop(AReg + tempres, false, true, true );
CReg:= (CReg and not Hflag) + halfcar;
end;
$C : PReg:= opaddr;
$D : begin {Subroutine Jumps}
if msn =$a then {Relative call}
opaddr:= PReg + extend(localop[1]);
PUSH (lo(PReg));
PUSH (hi(PReg)); {Stacked old P}
PReg:= opaddr; {Jump to S/R}
end;
$E : begin
opptr:= bytad(XReg);
Arithop(tempres, false, false, true );
end;
$F : begin
opptr:= bytad(memory[opaddr]);
Arithop(XReg, false, false, true);
end
end
end
end {End the OPCLASS Case}
end
else OneInstruction:= Illegal;
end
end; {End of Function OneInstruction}
{***********************************************************************
E M U L A T O R C O M M A N D R O U T I N E S
***********************************************************************}
procedure DoNothing; {Just a null function}
begin
end;
{******************************************************}
procedure AdditionInHex; {Hexadecimal addition}
var
x, y : integer; {The 2 arguments}
OK : boolean;
begin
OK:= false;
if Getvalue(x) then begin
if Getvalue(y) then begin
OK:= true; {Good input - proceed}
prefix:= 'Sum: @@@@, Diff: @@@@';
hexword( 6, x+y);
hexword(19, x-y);
writeln(prefix);
end
end;
if not OK then ReportError;
end;
{******************************************************}
procedure CompareMemoryBlocks; {Compare two blocks}
var
start, ending, second : integer;
begin
ClearLine;
prefix[0]:= chr(20); {Prepare a short line for output}
if Getrange(start,ending) then begin
if Getaddr(second) then begin {Get & verify input}
while (second <= memmax) and
(start <= ending ) and
(not KeyStop ) do begin
if memory[start] <> memory[second] then begin {Differs!}
hexword( 1,start);
hexbyte( 7,memory[start]);
hexbyte(11,memory[second]);
hexword(15,second);
writeln(prefix);
end;
start := start +1;
second:= second +1;
end
end
else
ReportError;
end
else
ReportError;
end;
{******************************************************}
procedure DisplayMemory; {Display in Hex. and Char. formats}
var
colpos, {Position in display line}
high : integer; {Display upper limit}
Procedure InnerDisplay;
begin
repeat
ClearLine;
prefix[31]:= '-'; {Group separator}
prefix[ 5]:= ':'; {Address delimiter}
hexword(1,low); {Start address}
repeat {Fill up line data}
colpos:= low mod 16; {Posn. in line}
hexbyte((colpos*3)+8, memory[low]); {Display, hex. & ASCII}
if chr(memory[low]) in [' '..'~'] then
prefix[colpos+57]:= chr(memory[low])
else
prefix[colpos+57]:= '.';
low:= low+1; {Next loxn.}
until ((low mod 16) =0) or (low > high);
write(copy(prefix,1,56));
lowvideo; write('['); highvideo;
write(copy(prefix,57,16));
lowvideo; writeln(']'); highvideo;
until low > high;
end;
begin {Display function, proper}
if Commandline[ComPtr] =CR then begin
high:= low +127; {No bounds given: default}
if high > memmax then high:= memmax;
InnerDisplay;
end
else if GetRange(low,high) then
InnerDisplay
else ReportError;
end;
{******************************************************}
procedure EnterNewData; {One byte at a time}
var
posn, {Locn. in Memory}
column : integer; {Display column no.}
entry : char; {Character entered}
Function EnterKey :char; {ENTER responses: hex. handled internally}
var
cct : integer; {Step count for hex. processing}
inch : char; {Character input}
begin
cct:= 1;
repeat
read(kbd,inch); {Get key: no echo, no edit}
inch:= upcase(inch);
if hex(inch) >= 0 then begin {Actions for hex. digit}
case cct of
1: begin
memory[posn]:= hex(inch);
write(inch);
end;
2: begin
memory[posn]:= (memory[posn] shl 4) + hex(inch);
write(inch);
end;
end; {End of the CASE}
cct:= cct+1;
end;
until inch in [' ', '-', CR];
if inch =CR then writeln
else write(inch);
EnterKey:= inch;
end;
begin {The command proper}
ClearLine;
if Getaddr(posn) then begin
if Commandline[ComPtr] =CR then begin {Single-byte mode}
repeat
clreol;
hexword(1,posn);
write(copy(prefix,1,4), ':');
column:= 8;
repeat
gotoxy(column,wherey); {Posn. for display}
hexbyte(1,memory[posn]);
write(copy(prefix,1,2), '.'); {Show current value}
entry:= EnterKey; {Hex. handled internally}
if entry =' ' then begin
posn:= posn+1;
column:= column+8; {To next point in line}
end
else begin
posn:= posn-1; {In case "-" entered}
column:= 100; {Force end-line}
end;
until (column > 64) or (posn > memmax);
writeln;
until (entry =CR) or (posn > memmax); {The only other char is CR}
end
else begin
if Getbytes then {Multiple byte-values on line}
for column:= 0 to valptr-1 do
memory[posn+column]:= valtab[column]
else ReportError;
end
end
else ReportError;
end;
{******************************************************}
procedure FillMemory; {Fill with a pattern}
var
start, ending, datptr : integer;
OK : boolean;
begin
OK:= Getrange(start,ending); {Get & validate data}
OK:= OK and Getbytes; {NB Use 3 separate stmts., to guarantee}
OK:= OK and (valptr >0); { order of execution}
if OK then begin
datptr:= 0;
while start <= ending do begin
if datptr >= valptr then datptr:= 0;
memory[start]:= valtab[datptr];
start := start +1;
datptr:= datptr +1;
end
end
else
ReportError;
end;
{******************************************************}
procedure GoRunProgram; {Run, with optional Breakpoints}
var
breakptr,
hold,
start :integer; {Starting point}
onbreak,
goodcmd :boolean;
rotary :array[0..14] of integer; {Rotary traceback table}
rotptr :integer;
ending :InstRes;
dummy :char;
const
breakcode :byte = $af; {Illegal instr., as breakpoint}
begin
goodcmd:= true;
start := PReg;
if Commandline[ComPtr] ='=' then begin
ComPtr := ComPtr +1; {Skip the "="}
goodcmd:= GetAddr(start); {Read the start}
end;
breakptr:= 0;
if GetAddr(hold) then begin
repeat
with BPlist[breakptr] do location:= hold;
breakptr:= breakptr +1;
until (not GetAddr(hold)) or (breakptr >9);
end;
if (Commandline[ComPtr] <> CR) or (not goodcmd) then
ReportError
else begin
for hold:= 0 to breakptr-1 do
with BPlist[hold] do begin {Set up breakpoints}
movedopc := memory[location];
memory[location]:= breakcode;
end;
SimTime:= 0; {Initialise cycle counter}
for rotptr:= 0 to 15 do rotary[rotptr]:= -1; {Clear traceback table}
rotptr:= 0;
PReg:= start; {Ready to go...}
repeat
rotary[rotptr]:= PReg;
rotptr:= (rotptr +1) mod 15; {Traceback}
ending:= OneInstruction; {Do once}
until (ending <> Success) or keypressed;
if keypressed then read(kbd,dummy); {Drop dummy keystroke}
ClearLine; {Blank line for traceback}
writeln(SimTime:8:0, ' Cycles Elapsed... Instruction Trace-Back:');
for hold:= 0 to 14 do begin
if rotary[rotptr] >= 0 then hexword(1 + 5*hold, rotary[rotptr]);
rotptr:= (rotptr+1) mod 15;
end;
writeln(prefix); {Write the traceback}
onbreak:= false;
if ending = Illegal then {Search breakpoint table}
for hold:= 0 to breakptr-1 do
with BPlist[hold] do
if location = PReg then onbreak:= true;
if onbreak then begin
writeln('Breakpoint');
for hold:= 0 to breakptr-1 do
with BPlist[hold] do {Cancel breakpoints}
memory[location]:= movedopc;
end
else
Showcause(ending);
DisplayAllRegisters;
end
end;
{******************************************************}
procedure HelpOnScreen; {Write the Emulator HELP messages}
var
holdup : char;
procedure Comline(lt, rt :filename); {Formatted HELP line}
var
ptr : integer;
begin
writeln;
highvideo;
ptr:= 1; {Start scan of Command}
repeat
write(lt[ptr]);
lowvideo;
ptr:= ptr+1;
until lt[ptr-1] =' ';
while ptr <= length(lt) do begin
if lt[ptr] in [',' , '='] then highvideo;
write(lt[ptr]);
lowvideo;
ptr:= ptr+1;
end;
highvideo;
write(' ':(26-length(lt)));
write(rt);
end;
begin
window(1,1,80,25);
savewindow(debugwind); {Save the old window}
promptline('{Hit any key to return to Emulator}');
if firsthelp then begin {First HELP - set up the display}
firsthelp:= false;
firstscreen;
clrscr;
writeln(' E M U L A T O R C O M M A N D S');
lowvideo;
writeln('<value> or <addr> = hexadecimal string');
writeln('<range> = <addr>,<addr> or <addr>L<value>');
writeln('<regname> = A X P S C');
writeln('Cmnds. may be abbreviated to 1 letter');
writeln(' but must be delimited by a non-alpha');
writeln('<space> and "," are equivalent');
writeln('[..] =optional, {..} =may be repeated');
highvideo;
writeln('Command Syntax Function');
Comline('Add value ,value', 'Hex. addition');
Comline('Compare range ,addr', 'Compare memory');
Comline('Display range', 'Display memory');
Comline('Enter addr [{,value}]', 'Show/alter memory');
Comline('Fill range {,value}', 'Fill mem. block');
Comline('Go [=addr] [{,addr}]', 'Run, & breakpoints');
Comline('Help ', 'Show this screen');
Comline('Move range ,addr', 'Move block in Mem.');
Comline('Quit ', 'Exit to Main Menu');
Comline('Register [regname]', 'Show/alter Regs.');
Comline('Search range {,value}', 'Search for data');
Comline('Trace [=addr] [,value]', 'Run & display');
Comline('View ', 'File-Viewer Window');
savewindow(helpwind); {Once window set up, save it}
end
else
showwindow(helpwind); {Subsequent calls - use fast-load}
read(kbd,holdup); {Wait for some key}
pulldebug(true); {Then put DEBUG back}
end;
{******************************************************}
procedure MoveMemoryBlock; {Move a block in memory}
var
start, ending, second : integer;
begin
if Getrange(start,ending) then begin
if Getaddr(second) then begin
while (second <= memmax) and
(start <= ending ) do begin
memory[second]:= memory[start];
start := start +1;
second:= second +1;
end
end
else
ReportError;
end
else
ReportError;
end;
{******************************************************}
procedure RegisterSet; {Display & change Registers}
begin
DisplayRegisters;
end;
{******************************************************}
procedure SearchForString; {Seek pattern in memory}
var
start, ending, subpt : integer;
OK : boolean;
begin
OK:= Getrange(start,ending); {Get & validate data}
OK:= OK and Getbytes; {NB Use 3 separate stmts., to guarantee}
OK:= OK and (valptr >0); { order of execution}
if OK then begin
ending:= ending +1 -valptr; {Don't search undersize strings}
repeat
subpt:= 0; {Look for match}
while (subpt < valptr) and
(memory[start + subpt] = valtab[subpt]) do subpt:= subpt +1;
if subpt = valptr then begin {Matched!}
prefix[0]:= chr(4);
hexword(1,start);
writeln(prefix);
end;
start:= start +1;
until KeyStop or (start > ending);
end
else
ReportError;
end;
{******************************************************}
procedure TraceExecution; {Machine emulation with Trace}
var
goodcmd :boolean;
start, {Start address}
tracect :integer; {Trace count}
ending :InstRes;
begin
start := PReg;
tracect:= 1;
goodcmd:= true;
if Commandline[ComPtr] ='=' then begin
ComPtr := ComPtr +1; {Pass the "="}
goodcmd:= GetAddr(start);
end;
if Commandline[ComPtr] in digit then begin
tracect:= 0;
while Commandline[ComPtr] in digit do begin
tracect:= tracect*10 + ord(Commandline[ComPtr]) -ord('0');
ComPtr:= ComPtr+1;
end;
PassGap;
end;
if Commandline[ComPtr] <> CR then goodcmd:= false;
if goodcmd then begin {The TRACE proper}
PReg:= start;
repeat
ending:= OneInstruction;
DisplayAllRegisters;
tracect:= tracect -1;
until (tracect <= 0) or (ending <> Success);
showcause(ending); {Report fault, if any}
end
else
ReportError;
end;
{********************* Emulator Mainline ***********************}
begin
if (listname <> Nofile) then begin
assign(viewfile,listname); {Get the Viewer file}
{$I-}
reset(viewfile); {Use LSTFILE - be sure it exists}
{$I+}
if (IOResult =0) then
close(viewfile) {Let Viewer open properly}
else begin
writeln('Cannot open Viewer file');
listname:= Nofile; {Open failed}
end
end;
if (listname <> Nofile) then Viewer(Initz); {Set up the Viewer module}
IntzRegs; {Simulates a machine reset}
with BPlist[0] do location:= -1; {Empty B-P table}
low:= 0; {Default for Display function}
firsthelp:= true;
CRTbase := hardware; {Set up CRT base pointer}
highvideo;
window(1,1,80,25); {No Turbo window}
clrscr; {Screen initialisations}
lowvideo;
gotoxy(1,baseline);
clreol; {Base-line in Low video}
CRTbase^[baseline, 1,character]:= horline; {Fixups at ends}
CRTbase^[baseline,80,character]:= horline;
hbar(baseleft, baseright);
pulldebug(false);
writeln('Emulator Ready: type "H <CR>" for Help');
repeat {Now run the Emulator}
GetLine(true); {Read & tidy command line}
case commandline[1] of
' ' : DoNothing;
'A' : AdditionInHex;
'C' : CompareMemoryBlocks;
'D' : DisplayMemory;
'E' : EnterNewData;
'F' : FillMemory;
'G' : GoRunProgram;
'H' : HelpOnScreen;
'M' : MoveMemoryBlock;
'Q' : DoNothing; {'Q' will end the REPEAT}
'R' : RegisterSet;
'S' : SearchForString;
'T' : TraceExecution;
'V' : if (listname <> Nofile) then Viewer(View)
else writeln('No View-file Attached');
else writeln('Unrecognised Command - Type "H" for Help');
end; {End of the CASE}
until Commandline[1] = 'Q'; {Loop until QUIT}
prefix:= '';
if (listname <> Nofile) then Viewer(Finish);
end;